package jp.co.nes.awssupport.sforce.batch;

import java.time.YearMonth;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.kohsuke.args4j.Option;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jp.co.nes.awssupport.access.dao.CreditCouponAssignedDao;
import jp.co.nes.awssupport.access.dao.TaxAssignedDao;
import jp.co.nes.awssupport.business.bean.CommonContainerBean;
import jp.co.nes.awssupport.business.bean.CommonContainerBean.ProcessingResult;
import jp.co.nes.awssupport.business.bean.CommonInfoBean;
import jp.co.nes.awssupport.business.logic.CompileProgressManage;
import jp.co.nes.awssupport.business.logic.ContractInformationManage;
import jp.co.nes.awssupport.common.base.AbstractActivityTaskClient;
import jp.co.nes.awssupport.common.base.CommonException;
import jp.co.nes.awssupport.common.bean.CreditCouponAssignedBean;
import jp.co.nes.awssupport.common.bean.TaxAssignedBean;
import jp.co.nes.awssupport.common.dao.ReadHandler;
import jp.co.nes.awssupport.common.dao.ReadType;
import jp.co.nes.awssupport.common.utility.BeanUtil;
import jp.co.nes.awssupport.common.utility.DateUtil;
import jp.co.nes.awssupport.common.utility.DbConnUtil;

/**
 * Sforce反映です。<br>
 * クレジット履歴と利用実績をサポートポータルへ反映します。
 */
public class SforceUpdate extends AbstractActivityTaskClient<CommonInfoBean, CommonContainerBean<CommonInfoBean>> {

    /** ロガー */
    private static Logger logger = LoggerFactory.getLogger(SforceUpdate.class);

    /** アクティビティのarn(コマンドライン引数で設定) */
    @Option(name = "-aarn", aliases = "--activityArn", usage = "アクティビティのarn", metaVar = "activityArn", required = true)
    private String activityArn;

    /** 契約情報管理 */
    private ContractInformationManage ciManage;

    /** Sforce反映を実施する連結アカウントIDリスト */
    private List<String> sforceUpdateLinkedAccountIdList;

    /**
     * メインメソッドです。
     *
     * @param args コマンドライン引数
     */
    public static void main(String[] args) {
        SforceUpdate client = new SforceUpdate();
        client.execute(args);
    }

    /**
     * デフォルトコンストラクタです。
     */
    public SforceUpdate() {
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.common.base.AbstractActivityTaskClient#getActivityArn()
     */
    @Override
    protected String getActivityArn() {
        return activityArn;
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.common.base.AbstractActivityTaskClient#getInputClass()
     */
    @Override
    protected Class<CommonInfoBean> getInputClass() {
        return CommonInfoBean.class;
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.common.base.AbstractActivityTaskClient#runActivityTask(jp.co.nes.awssupport.common.bean.BaseBean)
     */
    @Override
    protected CommonContainerBean<CommonInfoBean> runActivityTask(CommonInfoBean input) {
        String targetYearMonthValue = input.getTargetYearMonthValue();
        YearMonth targetYearMonth = DateUtil.toYearMonth(targetYearMonthValue);

        String[] ids = null;
        Map<String, String> other = input.getOther();
        if (other != null) {
            String value = other.get("sforceUpdateLinkedAccountIds");
            if (value != null) {
                ids = value.split(",");
            }
        }

        CompileProgressManage cpManage = new CompileProgressManage(targetYearMonth);
        if (ids == null || ids.length == 0) {
            logger.debug("ids == null || ids.length == 0");
            sforceUpdateLinkedAccountIdList = cpManage.getOkSforceUpdateLinkedAccountIdList();
        } else {
            logger.debug("ids != null && ids.length != 0");
            sforceUpdateLinkedAccountIdList = Arrays.asList(ids);
        }
        logger.info("sforceUpdateLinkedAccountIdList.size()=" + sforceUpdateLinkedAccountIdList.size());
        try {
            boolean isConfirmedBillingCsv = cpManage.isConfirmedBillingCsv();
            ciManage = new ContractInformationManage(targetYearMonth);
            if (isConfirmedBillingCsv) {
                addCreditCouponHistory(targetYearMonth);
            }
            addUsageHistory(targetYearMonth);

            if (isConfirmedBillingCsv) {
                ciManage.saveCreditCouponAndUsageHistory();
            } else {
                ciManage.saveUsageHistory();
            }
        } catch (Throwable e) {
            throw new CommonException(e);
        } finally {
            DbConnUtil.closeAll();
        }

        // 返却内容の作成
        CommonInfoBean info = new CommonInfoBean();
        BeanUtil.copyProperties(info, input);
        CommonContainerBean<CommonInfoBean> output = new CommonContainerBean<>();
        output.setInfoBean(info);
        output.setProcessingResult(ProcessingResult.SUCCESS);
        return output;
    }

    /**
     * 反映するクレジット履歴を登録します。
     *
     * @param targetYearMonth 処理対象年月
     */
    private void addCreditCouponHistory(YearMonth targetYearMonth) {
        // 検索条件の作成
        Object[] conditions = new Object[1];
        conditions[0] = DateUtil.toInt(targetYearMonth);

        // クレジット適用を読み込む
        Class<CreditCouponAssignedBean> cls = CreditCouponAssignedBean.class;
        CreditCouponAssignedDao dao = new CreditCouponAssignedDao();
        ReadType readType = CreditCouponAssignedDao.DaoReadType.YEAR_MONTH;
        dao.read(new ReadHandler<CreditCouponAssignedBean>(cls, readType) {
            /*
             * (非 Javadoc)
             * @see jp.co.nes.awssupport.common.dao.ReadHandler#read(jp.co.nes.awssupport.common.bean.BaseBean)
             */
            @Override
            protected void read(CreditCouponAssignedBean ccaBean) {
                String linkedAccountId = ccaBean.getLinkedAccountId();
                if (sforceUpdateLinkedAccountIdList.stream().anyMatch(id -> id.equals(linkedAccountId))) {
                    ciManage.add(ccaBean);
                }
            }
        }, conditions);
    }

    /**
     * 反映する利用実績を登録します。
     *
     * @param targetYearMonth 処理対象年月
     */
    private void addUsageHistory(YearMonth targetYearMonth) {
        // 検索条件の作成
        Object[] conditions = new Object[1];
        conditions[0] = DateUtil.toInt(targetYearMonth);

        // 税金適用を読み込む(「連結アカウントID, 年月」単位で集計した内容)
        Class<TaxAssignedBean> cls = TaxAssignedBean.class;
        TaxAssignedDao dao = new TaxAssignedDao();
        ReadType readType = TaxAssignedDao.DaoReadType.TOTALIZATION_YEAR_MONTH;
        dao.read(new ReadHandler<TaxAssignedBean>(cls, readType) {
            /*
             * (非 Javadoc)
             * @see jp.co.nes.awssupport.common.dao.ReadHandler#read(jp.co.nes.awssupport.common.bean.BaseBean)
             */
            @Override
            protected void read(TaxAssignedBean taBean) {
                String linkedAccountId = taBean.getLinkedAccountId();
                if (sforceUpdateLinkedAccountIdList.stream().anyMatch(id -> id.equals(linkedAccountId))) {
                    ciManage.add(taBean);
                }
            }
        }, conditions);
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.common.base.AbstractClient#debugArgument()
     */
    @Override
    protected void debugArgument() {
        if (logger.isDebugEnabled()) {
            logger.debug("activityArn=" + activityArn);
        }
    }
}
